linux网络编程

您所在的位置:网站首页 linux socket通信流程 linux网络编程

linux网络编程

#linux网络编程| 来源: 网络整理| 查看: 265

服务端流程步骤

socket函数创建监听套接字lfd

bind函数将监听套接字绑定ip和端口

listen函数设置服务器为被动监听状态,同时创建一条未完成连接队列(没走完tcp三次握手流程的连接),和一条已完成连接队列(已完成tcp三次握手的连接)

accept函数循环的从已完成连接队列中提取连接,并返回一个新的套接字cfd跟客户端进行通信

fork函数创建一个子进程,让子进程与客户端进行通信

子进程:read函数循环的从r缓冲区读取客户端发送的数据,write函数将要发送的数据写入w缓冲区

close函数关闭套接字

客户端流程步骤

socket函数创建套接字

connect函数连接服务器

write函数将要发送的数据写入w缓冲区,read函数从r缓冲区读取服务器发送给客户端的数据

close函数关闭套接字

客户端跟服务器通信流程图相关函数

int socket(int domain, int type, int protocol);

功能:创建一个用于网络通信的套接字文件描述符

参数:domain:协议族(AF_INET:ipv4,AF_INET6:ipv6,等等)

type:套接字类型(SOCK_DGRAM:udp,SOCK_STREAM:tcp,等等)

protocol:用于制定某个协议的特定类型,即type类型中的某个类型,通常不用管它,设置 为 0

返回值:成功则返回socket套接字描述符, 失败返回-1,并设置errno

头文件:#include

int bind(int sockfd, struct sockaddr *my_addr, socklen_t addrlen);

功能:将sockfd绑定ip和端口

参数:sockfd:套接字

my_addr:存放有协议,ip,端口的结构体信息

addrlen:my_addr结构体大小

返回值:成功返回0,失败返回-1,并设置errno

头文件:#include

#include

int listen(int s, int backlog);

功能:让服务器处于被动监听状态,同时创建了一条未完成三次握手的连接队列和一条已经完成三次握 手的连接队列

参数:s:套接字

backlog:支持未完成连接和已完成连接之和的最大值,一般设置128

返回值:成功返回0,失败返回-1,并设置errno

头文件:#include

int accept(int s, struct sockaddr *addr, socklen_t *addrlen);

功能:从已完成连接队列中提取客户端连接

参数:s:套接字

addr:存放成功连接的客户端的ip,端口等信息结构体

addrlen:存放addr结构体大小的变量地址

返回值:成功则返回一个非负整数标识这个连接套接字,是否返回-1

头文件:#include

#include

ssize_t read(int fd, void *buf, size_t count);

功能:从文件描述符 fd 中读取 count 字节的数据并放入从 buf 开始的缓冲区中

参数:fd:文件描述符

buf:缓冲区

count:读count字节

返回值:成功时返回读取到的字节数,失败返回-1,并设置errno

头文件:#include

ssize_t write(int fd, const void *buf, size_t count);

功能:向文件描述符fd所引用的文件中写入从buf开始的缓冲区中count字节的数据

参数:fd:文件描述符

buf:缓冲区

count:写count字节

返回值:功时返回所写入的字节数,失败返回-1,并设置errno

头文件:#include

int close(int fd);

功能:关闭 一个文件描述符

参数:fd:要关闭的文件描述符

返回值:成功返回0,失败返回-1,并设置errno

头文件:#include

int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

功能:连接服务器

参数:sockfd:套接字

addr:服务器的ip,端口等结构体信息

addrlen:addr结构体大小

返回值:成功返回0,失败返回-1,并设置errno

头文件:#include

pid_t fork(void);

功能:创建一个子进程

参数:无

返回值:父进程返回子进程的进程id,子进程返回0

头文件:#include

int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);

功能:设置信号集屏蔽字

参数:how:SIG_BLOCK (mask |= set),SIG_UNBLOCK (mask &= ~set),SIG_SETMASK (mask = set)

set:信号集

oldset:旧的信号集

返回值:成功返回0,失败返回-1,并设置errno

头文件:#include

pid_t waitpid(pid_t pid, int *status, int options);

功能:回收已结束的子进程资源

参数:pid:pid0 等待任何子进程识别码为pid的子进程

status:子进程的结束状态值

options:WNOHANG 如果没有任何已经结束的子进程则马上返回, 不予以等待

WUNTRACED 如果子进程进入暂停执行情况则马上返回, 但结束状态不予以理会

返回值:成功返回子进程pid,失败返回-1

头文件: #include

#include

服务端代码#include #include #include #include #include #include #include #include #include #include #define BUF_SIZE 256void do_sigchld(int signo, siginfo_t *siginfo, void *p){ int status; pid_t pid; while((pid = waitpid(0, &status, WNOHANG)) > 0) //0:回收跟调用进程同组的子进程的资源,WNOHANG:不阻塞 { if (WIFEXITED(status)) printf("pid = %d, parent pid = %d, child pid = %d, exit status %d\", pid, getpid(), siginfo->si_pid, WEXITSTATUS(status)); else if (WEXITSTATUS(status)) printf("pid = %d, parent pid = %d, child pid = %d, exit by signal %d ", pid, getpid(), siginfo->si_pid, WIFSIGNALED(status)); }}void sys_err(const char *str, int err){ perror(str); exit(err);}int main(int argc, char *argv[]){ if (argc < 2) { printf("%s port\", argv[0]); exit(1); } //创建流式套接字 int lfd = socket(AF_INET, SOCK_STREAM, 0); if (lfd < 0) sys_err("socket", 1); //绑定ip端口 struct sockaddr_in server_addr; server_addr.sin_family = AF_INET; server_addr.sin_port = htons((unsigned short)atoi(argv[1])); server_addr.sin_addr.s_addr = 0; //0表示将本机所有ip都绑定上 int ret = bind(lfd, (struct sockaddr *)&server_addr, sizeof(server_addr)); if (ret < 0) sys_err("bind", 1); //监听 ret = listen(lfd, 128); if (ret < 0) sys_err("listen", 1); //阻塞SIGCHLD信号 sigset_t set; sigemptyset(&set); sigaddset(&set, SIGCHLD); sigprocmask(SIG_BLOCK, &set, NULL); int block = 1; //循环提取 int cfd; pid_t pid; struct sockaddr_in client_addr; socklen_t len = sizeof(client_addr); char buf[BUF_SIZE]; ssize_t size; char ip[INET_ADDRSTRLEN] = ""; while(1) { cfd = accept(lfd, (struct sockaddr *)&client_addr, &len); if (cfd < 0) { if (errno == EINTR) continue; sys_err("accept", 1); } printf("client ip = %s, port = %d connect success\", inet_ntop(AF_INET, &client_addr.sin_addr.s_addr, ip, sizeof(ip)), ntohs(client_addr.sin_port)); pid = fork(); if (pid == 0) { //in child close(lfd); //关闭不用了的监听套接字 //解除阻塞SIGCHLD信号 sigprocmask(SIG_UNBLOCK, &set, NULL); block = 0; while(1) { memset(buf, 0, sizeof(buf)); size = read(cfd, buf, sizeof(buf)); if (size == 0) //客户端断开连接 { printf("client close\"); break; } printf("%s\", buf); write(cfd, buf, size); } break; } else if (pid > 0) { //in parent close(cfd); //关闭不用了的跟客户端通讯的套接字 if (1 == block) { //先捕捉 struct sigaction sa; sa.sa_sigaction = do_sigchld; sigemptyset(&sa.sa_mask); sa.sa_flags = SA_SIGINFO; sigaction(SIGCHLD, &sa, NULL); //后解除阻塞 sigprocmask(SIG_UNBLOCK, &set, NULL); block = 0; } } else sys_err("fork", 1); } //关闭套接字 if (pid == 0) close(cfd); else if (pid > 0) close(lfd); return 0;}客户端代码#include #include #include #include #include #include int main(int argc, char *argv[]){ if (argc < 3) { printf("%s sever_ip server_port\", argv[0]); exit(1); } //创建流式套接字 int fd = socket(AF_INET, SOCK_STREAM, 0); if (fd < 0) { perror("socket"); exit(1); } //连接服务器 struct sockaddr_in addr; addr.sin_family = AF_INET; addr.sin_port = htons((unsigned short)atoi(argv[2])); addr.sin_addr.s_addr = inet_addr(argv[1]); int ret = connect(fd, (struct sockaddr *)&addr, sizeof(addr)); printf("connect ret = %d\", ret); if (ret < 0) { perror("connect"); exit(1); } //读写数据 char buf_w[128] = ""; char buf_r[128] = ""; ssize_t size_r = 0; while(1) { fgets(buf_w, sizeof(buf_w), stdin); buf_w[strlen(buf_w) - 1] = 0; write(fd, buf_w, strlen(buf_w)); size_r = read(fd, buf_r, sizeof(buf_r)); if (size_r == 0) //服务器断开 break; else printf("%s\", buf_r); memset(buf_w, 0, sizeof(buf_w)); memset(buf_r, 0, sizeof(buf_r)); } //关闭套接字 close(fd); return 0;}结果

3个客户端连接服务器时

服务端

客户端

ps aux 可以看到有4个服务器进程(其中一个是主进程,用于监听处理新的连接,其他3个子进程用于跟客户端进行通信)

回射服务信息截图

客户端1:

客户端2:

客户端3:

服务器收到进行打印:

3个客户端都退出时

服务端收到客户端退出,并回收跟客户端进行通信的3个子进程的资源

ps aux 查看可以看到只剩主进程,用于监听处理新的连接,其他3个子进程都已结束



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3